{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "name": "TF Lite Week 1 Exercise - Answer",
      "version": "0.3.2",
      "provenance": [],
      "collapsed_sections": [],
      "toc_visible": true
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "accelerator": "GPU"
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ka96-ajYzxVU",
        "colab_type": "text"
      },
      "source": [
        "# Module 1 Exercise - Answer (Fashion MNIST)\n",
        "Train your own model and convert it to TFLite\n",
        "\n",
        "This notebook uses the [Fashion MNIST](https://github.com/zalandoresearch/fashion-mnist) dataset which contains 70,000 grayscale images in 10 categories. The images show individual articles of clothing at low resolution (28 by 28 pixels), as seen here:\n",
        "\n",
        "<table>\n",
        "  <tr><td>\n",
        "    <img src=\"https://tensorflow.org/images/fashion-mnist-sprite.png\"\n",
        "         alt=\"Fashion MNIST sprite\"  width=\"600\">\n",
        "  </td></tr>\n",
        "  <tr><td align=\"center\">\n",
        "    <b>Figure 1.</b> <a href=\"https://github.com/zalandoresearch/fashion-mnist\">Fashion-MNIST samples</a> (by Zalando, MIT License).<br/>&nbsp;\n",
        "  </td></tr>\n",
        "</table>\n",
        "\n",
        "Fashion MNIST is intended as a drop-in replacement for the classic [MNIST](http://yann.lecun.com/exdb/mnist/) dataset—often used as the \"Hello, World\" of machine learning programs for computer vision. The MNIST dataset contains images of handwritten digits (0, 1, 2, etc.) in a format identical to that of the articles of clothing we'll use here.\n",
        "\n",
        "This uses Fashion MNIST for variety, and because it's a slightly more challenging problem than regular MNIST. Both datasets are relatively small and are used to verify that an algorithm works as expected. They're good starting points to test and debug code.\n",
        "\n",
        "We will use 60,000 images to train the network and 10,000 images to evaluate how accurately the network learned to classify images. You can access the Fashion MNIST directly from TensorFlow. Import and load the Fashion MNIST data directly from TensorFlow:"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rjOAfhgd__Sp",
        "colab_type": "text"
      },
      "source": [
        "# Setup"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Bp_nvHnh_tDo",
        "colab_type": "code",
        "outputId": "89209e90-4b8f-4f52-af92-a53822f1327d",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 72
        }
      },
      "source": [
        "!pip3 install -q tensorflow-gpu==2.0.0-beta1"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "\u001b[K     |████████████████████████████████| 368.0MB 65kB/s \n",
            "\u001b[K     |████████████████████████████████| 3.2MB 28.3MB/s \n",
            "\u001b[K     |████████████████████████████████| 450kB 39.8MB/s \n",
            "\u001b[?25h"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "pfyZKowNAQ4j",
        "colab_type": "code",
        "outputId": "8a94ac17-d4e7-474f-e984-a5ed389f5352",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "from __future__ import absolute_import, division, print_function, unicode_literals\n",
        "\n",
        "# TensorFlow and tf.keras\n",
        "import tensorflow as tf\n",
        "from tensorflow import keras\n",
        "\n",
        "# Helper libraries\n",
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "import pathlib\n",
        "from google.colab import files\n",
        "\n",
        "\n",
        "print(tf.__version__)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "2.0.0-dev20190628\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tadPBTEiAprt",
        "colab_type": "text"
      },
      "source": [
        "# Download Fashion MNIST Dataset"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "jmSkLCyRKqKB",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "import tensorflow_datasets as tfds\n",
        "tfds.disable_progress_bar()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "XcNwi6nFKneZ",
        "colab_type": "code",
        "outputId": "8e0d8173-6dbd-4ef5-a70b-efc8e9d33802",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 156
        }
      },
      "source": [
        "splits = tfds.Split.ALL.subsplit(weighted=(80, 10, 10))\n",
        "\n",
        "splits, info = tfds.load('fashion_mnist', with_info=True, as_supervised=True, split=splits)\n",
        "\n",
        "(train_examples, validation_examples, test_examples) = splits\n",
        "\n",
        "num_examples = info.splits['train'].num_examples\n",
        "num_classes = info.features['label'].num_classes"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "\u001b[1mDownloading and preparing dataset fashion_mnist (29.45 MiB) to /root/tensorflow_datasets/fashion_mnist/1.0.0...\u001b[0m\n"
          ],
          "name": "stdout"
        },
        {
          "output_type": "stream",
          "text": [
            "WARNING: Logging before flag parsing goes to stderr.\n",
            "W0701 11:01:27.036766 139937208235904 deprecation.py:323] From /usr/local/lib/python3.6/dist-packages/tensorflow_datasets/core/file_format_adapter.py:209: tf_record_iterator (from tensorflow.python.lib.io.tf_record) is deprecated and will be removed in a future version.\n",
            "Instructions for updating:\n",
            "Use eager execution and: \n",
            "`tf.data.TFRecordDataset(path)`\n"
          ],
          "name": "stderr"
        },
        {
          "output_type": "stream",
          "text": [
            "\u001b[1mDataset fashion_mnist downloaded and prepared to /root/tensorflow_datasets/fashion_mnist/1.0.0. Subsequent calls will reuse this data.\u001b[0m\n"
          ],
          "name": "stdout"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "-eAv71FRm4JE",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "class_names = ['T-shirt_top', 'Trouser', 'Pullover', 'Dress', 'Coat',\n",
        "               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "hXe6jNokqX3_",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "with open('labels.txt', 'w') as f:\n",
        "  f.write('\\n'.join(class_names))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "iubWCThbdN8K",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "IMG_SIZE = 28"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ZAkuq0V0Aw2X",
        "colab_type": "text"
      },
      "source": [
        "# Preprocessing data"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_5SIivkunKCC",
        "colab_type": "text"
      },
      "source": [
        "## Preprocess"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "BwyhsyGydHDl",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "def format_example(image, label):\n",
        "  image = tf.cast(image, tf.float32)\n",
        "  image = tf.image.resize(image, (IMG_SIZE, IMG_SIZE))\n",
        "  image = image / 255.0\n",
        "  return image, label"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "HAlBlXOUMwqe",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "BATCH_SIZE = 32"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JM4HfIJtnNEk",
        "colab_type": "text"
      },
      "source": [
        "## Create a Dataset from images and labels"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "uxe2I3oxLDhq",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "train_batches = train_examples.shuffle(num_examples//4).map(format_example).batch(BATCH_SIZE).prefetch(1)\n",
        "validation_batches = validation_examples.shuffle(num_examples//4).map(format_example).batch(BATCH_SIZE)\n",
        "test_batches = test_examples.map(format_example).batch(1)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "M-topQaOm_LM",
        "colab_type": "text"
      },
      "source": [
        "# Building the model"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "kDqcwksFB1bh",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "model = tf.keras.Sequential([\n",
        "  tf.keras.layers.Conv2D(16, 3, activation='relu', input_shape=(IMG_SIZE, IMG_SIZE, 1)),\n",
        "  tf.keras.layers.MaxPooling2D(),\n",
        "  tf.keras.layers.Conv2D(32, 3, activation='relu'),\n",
        "  tf.keras.layers.Flatten(),\n",
        "  tf.keras.layers.Dense(64, activation='relu'),\n",
        "  tf.keras.layers.Dense(10, activation='softmax')\n",
        "])\n",
        "\n",
        "\n",
        "\n",
        "model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])\n"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zEMOz-LDnxgD",
        "colab_type": "text"
      },
      "source": [
        "## Train"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "JGlNoRtzCP4_",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "model.fit(train_batches, \n",
        "          epochs=10,\n",
        "          validation_data=validation_batches)"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TZT9-7w9n4YO",
        "colab_type": "text"
      },
      "source": [
        "# Exporting to TFLite"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "9dq78KBkCV2_",
        "colab_type": "code",
        "outputId": "41b1e939-7c48-4859-a552-d6961ec38d33",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 88
        }
      },
      "source": [
        "export_dir = 'saved_model/1'\n",
        "tf.saved_model.save(model, export_dir)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "stream",
          "text": [
            "W0701 11:05:28.637118 139937208235904 deprecation.py:506] From /usr/local/lib/python3.6/dist-packages/tensorflow_core/python/ops/resource_variable_ops.py:1775: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.\n",
            "Instructions for updating:\n",
            "If using Keras pass *_constraint arguments to layers.\n"
          ],
          "name": "stderr"
        }
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "EDGiYrBdE6fl",
        "colab_type": "code",
        "cellView": "form",
        "colab": {}
      },
      "source": [
        "#@title Select mode of optimization\n",
        "mode = \"Speed\" #@param [\"Default\", \"Storage\", \"Speed\"]\n",
        "\n",
        "if mode == 'Storage':\n",
        "  optimization = tf.lite.Optimize.OPTIMIZE_FOR_SIZE\n",
        "elif mode == 'Speed':\n",
        "  optimization = tf.lite.Optimize.OPTIMIZE_FOR_LATENCY\n",
        "else:\n",
        "  optimization = tf.lite.Optimize.DEFAULT"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "RbcS9C00CzGe",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Convert the model.\n",
        "converter = tf.lite.TFLiteConverter.from_saved_model(export_dir)\n",
        "converter.optimizations = [optimization]\n",
        "tflite_model = converter.convert()"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "q5PWCDsTC3El",
        "colab_type": "code",
        "outputId": "97349e68-0bff-41cd-ad48-90a6abb85f11",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 34
        }
      },
      "source": [
        "tflite_model_file = pathlib.Path('/content/model.tflite')\n",
        "tflite_model_file.write_bytes(tflite_model)"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "356880"
            ]
          },
          "metadata": {
            "tags": []
          },
          "execution_count": 18
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SR6wFcQ1Fglm",
        "colab_type": "text"
      },
      "source": [
        "# Test the model with TFLite interpreter "
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "rKcToCBEC-Bu",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Load TFLite model and allocate tensors.\n",
        "interpreter = tf.lite.Interpreter(model_content=tflite_model)\n",
        "interpreter.allocate_tensors()\n",
        "\n",
        "input_index = interpreter.get_input_details()[0][\"index\"]\n",
        "output_index = interpreter.get_output_details()[0][\"index\"]"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "E8EpFpIBFkq8",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "# Gather results for the randomly sampled test images\n",
        "predictions = []\n",
        "test_labels = []\n",
        "test_images = []\n",
        "\n",
        "for img, label in test_batches.take(50):\n",
        "  interpreter.set_tensor(input_index, img)\n",
        "  interpreter.invoke()\n",
        "  predictions.append(interpreter.get_tensor(output_index))\n",
        "  test_labels.append(label[0])\n",
        "  test_images.append(np.array(img))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "kSjTmi05Tyod",
        "colab_type": "code",
        "cellView": "form",
        "colab": {}
      },
      "source": [
        "#@title Utility functions for plotting\n",
        "# Utilities for plotting\n",
        "\n",
        "def plot_image(i, predictions_array, true_label, img):\n",
        "  predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]\n",
        "  plt.grid(False)\n",
        "  plt.xticks([])\n",
        "  plt.yticks([])\n",
        "  \n",
        "  img = np.squeeze(img)\n",
        "\n",
        "  plt.imshow(img, cmap=plt.cm.binary)\n",
        "\n",
        "  predicted_label = np.argmax(predictions_array)\n",
        "  if predicted_label == true_label.numpy():\n",
        "    color = 'green'\n",
        "  else:\n",
        "    color = 'red'\n",
        "    \n",
        "  plt.xlabel(\"{} {:2.0f}% ({})\".format(class_names[predicted_label],\n",
        "                                100*np.max(predictions_array),\n",
        "                                class_names[true_label]),\n",
        "                                color=color)\n",
        "\n",
        "def plot_value_array(i, predictions_array, true_label):\n",
        "  predictions_array, true_label = predictions_array[i], true_label[i]\n",
        "  plt.grid(False)\n",
        "  plt.xticks(list(range(10)))\n",
        "  plt.yticks([])\n",
        "  thisplot = plt.bar(range(10), predictions_array[0], color=\"#777777\")\n",
        "  plt.ylim([0, 1])\n",
        "  predicted_label = np.argmax(predictions_array[0])\n",
        "\n",
        "  thisplot[predicted_label].set_color('red')\n",
        "  thisplot[true_label].set_color('blue')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "ZZwg0wFaVXhZ",
        "colab_type": "code",
        "outputId": "f9676edc-f305-4115-938b-389286d2228d",
        "cellView": "form",
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 201
        }
      },
      "source": [
        "#@title Visualize the outputs { run: \"auto\" }\n",
        "index = 49 #@param {type:\"slider\", min:1, max:50, step:1}\n",
        "plt.figure(figsize=(6,3))\n",
        "plt.subplot(1,2,1)\n",
        "plot_image(index, predictions, test_labels, test_images)\n",
        "plt.show()"
      ],
      "execution_count": 0,
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "image/png": "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\nywAAAABJRU5ErkJggg==\n",
            "text/plain": [
              "<Figure size 432x216 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          }
        }
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "076bo3FMpRDb",
        "colab_type": "text"
      },
      "source": [
        "# Download TFLite model and assets"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "XsPXqPlgZPjE",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "files.download(tflite_model_file)\n",
        "files.download('labels.txt')"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "H8t7_jRiz9Vw",
        "colab_type": "text"
      },
      "source": [
        "# Prepare the test images for download (Optional)"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "Fi09nIps0gBu",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "!mkdir -p test_images"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "sF7EZ63J0hZs",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "from PIL import Image\n",
        "\n",
        "for index, (image, label) in enumerate(test_batches.take(50)):\n",
        "  image = tf.cast(image * 255.0, tf.uint8)\n",
        "  image = tf.squeeze(image).numpy()\n",
        "  pil_image = Image.fromarray(image)\n",
        "  pil_image.save('test_images/{}_{}.jpg'.format(class_names[label[0]].lower(), index))"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "uM35O-uv0iWS",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "!ls test_images"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "aR20r4qW0jVm",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "!zip -qq fmnist_test_images.zip -r test_images/"
      ],
      "execution_count": 0,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {
        "id": "tjk4537X0kWN",
        "colab_type": "code",
        "colab": {}
      },
      "source": [
        "files.download('fmnist_test_images.zip')"
      ],
      "execution_count": 0,
      "outputs": []
    }
  ]
}